package com.shop.service.impl;

import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shop.entity.ShopFile;
import com.shop.mapper.ShopFileMapper;
import com.shop.service.ShopFileService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.utils.FileNameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * <p>
 * 文件表 服务实现类
 * </p>
 *
 * @author lpx610
 * @since 2023-10-31
 */
@Service
public class ShopFileServiceImpl extends ServiceImpl<ShopFileMapper, ShopFile> implements ShopFileService {

    @Value("${minio.url}")
    String url;
    @Value("${minio.username}")
    String username;
    @Value("${minio.password}")
    String password;

    @Override
    public String upload(String bucket, MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //获取md5 大小 类型
        String md5 = DigestUtils.md5Hex(file.getInputStream());
        long size = file.getSize();
        String type = file.getContentType();
        //判断是否成功上传过
        ShopFile shopFile = get(md5, size, type, bucket);
        //如果上传过 无需再传 直接返回曾经上传的路径
        if (shopFile != null) {
            return shopFile.getPath();
        }

        //拼接新文件名
        StringBuilder fileName = new StringBuilder(NanoIdUtils.randomNanoId())
                .append(".")
                .append(FileNameUtils.getExtension(file.getOriginalFilename()));

        //创建客户端 需要通过：地址、用户名、密码
        MinioClient client = MinioClient.builder()
                .endpoint(url)
                .credentials(username, password)
                .build();
        //构建PutObjectArgs
        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(bucket)   //传到哪个minio桶里
                .contentType(type)     //文件类型
                .object(fileName.toString())     //文件名
                .stream(file.getInputStream(), size, 0)   //字节流，文件大小，切多少块
                .build();
        //上传文件到Minio
        client.putObject(args);

        //path == 桶名+文件名
        String path = "/" + bucket + "/" + fileName.toString();

        //如果没上传过 需要将信息保存到数据库中，下次就能检索到已上传的了
        shopFile = new ShopFile(md5, size, type, path, bucket);
        save(shopFile);
        return path;
    }

    private ShopFile get(String md5, Long size, String type, String bucket) {
        QueryWrapper<ShopFile> qw = new QueryWrapper<>();
        qw.eq("md5", md5).eq("size", size).eq("type", type).eq("bucket", bucket);
        return this.getOne(qw);
    }
}
